#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "environment.h"
#include "predator.h"
#include "prey.h"
#include <iomanip>

using namespace std;

int main () {

	// Randomizing number generator
	srand( time( NULL ) );

	int menuSelect, timer;

	cout << setprecision(4) << fixed;

	// Loading environment
	Environment env;

	// Creating predators and Preys
	Predator * pred = new Predator(&env);
	Prey * prey = new Prey(&env);

	// Loading actors into the environment
	env.addPredator(pred, 0, 0);
	env.addPrey(prey, 5, 5);

	// Printing introduction
	cout << "\n\nAutonomous Agents Lab - Assignment 2\n";
	cout << "Selection menu:\n\n";

	do {

	// Printing Menu
	cout << "Enter 1 to execute the simulation of the environment;\n";
	cout << "Enter 2 to print the predator's current parameters;\n";
	cout << "Enter 3 to print the predator's current Q values;\n";
	cout << "Enter 4 to change the predator's parameters ( will reset learning );\n";
	cout << "Enter 5 to restart the predator's learning;\n";
	cout << "Enter 6 to change the predator's algorithm;\n";
	cout << "Enter 0 to exit;\n\n";
	cin >> menuSelect;
	cout << "\n";

	timer = clock();

	switch ( menuSelect ) {

		// SIMULATION WITH SET PARAMETERS
		case 1: {
			int selection, episodes;
			env.setPrint(false);

			do {
			cout << "Enter 1 to execute a single episode and to print all moves;\n";
			cout << "Enter 2 to execute 100 episodes;\n";
			cout << "Enter 3 to execute 1000 episodes;\n";
			cout << "Enter 4 to execute k episodes;\n\n";
			cin >> selection;
			cout << "\n";
			switch ( selection ) {
				case 1:
					env.setPrint(true);
					// Set the simulation printing on
					episodes = 1;
					break;
				case 2:
					episodes = 100;
					break;
				case 3:
					episodes = 1000;
					break;
				case 4:
					cout << "Enter k:\n";
					cin >> episodes;
					break;
				default:
					cout << "Invalid selection, please enter one of the following:\n\n";
			}
			} while ( selection < 1 || selection > 4 );

			cout << "Starting Simulation(s)...\n\n";

			// Reset starting timer because we had to wait for input
			timer = clock();

			for ( int i = 0; i < episodes; i++ )
			    env.startSimulation();
		}	// End of simulation
        break;

		// PRINT PARAMETERS
		case 2:
			pred->printParameters();
		break;

		// PRINT Q MATRIX ( prey in 5,5 and action is up ( 0 ) )
		case 3:
			pred->printQ(0);
		break;

		// PARAMETER CHANGE
		case 4: {
			double gamma, alpha, epsilon, temperature;
			cout << "Enter new value for alpha:\n";
			cin >> alpha;
			cout << "\nEnter new value for epsilon:\n";
			cin >> epsilon;
			cout << "\nEnter new value for gamma:\n";
			cin >> gamma;
			cout << "\nEnter new value for temperature:\n";
            cin >> temperature;

			pred->setAlpha(alpha);
			pred->setEpsilon(epsilon);
			pred->setGamma(gamma);
			pred->setTemperature(temperature);

			cout << "\n";
		}
		// We pass through to case 4 to forget learning

		// PREDATOR FORGETS LEARNING
		case 5:
			{
			double newQ;
			cout << "Enter new value for Q initialization:\n";
			cin >> newQ;
			pred->resetQ(newQ);
		}
		break;

		// ALGORITHM CHANGE
		case 6: {
			int selection;

			do {
			cout << "Enter 0 for random policy;\n";
			cout << "Enter 1 for Epsilon-greedy Q-learning;\n";
			cout << "Enter 2 for Softmax Q-learning;\n";
			cout << "Enter 3 for Epsilon-greedy SARSA;\n";
			cout << "Enter 4 for Softmax SARSA;\n";
			cout << "Enter 5 for Epsilon-greedy on policy Monte Carlo;\n";
			cout << "Enter 6 for Softmax on policy Monte Carlo;\n";
			cout << "Enter 7 for Epsilon-greedy off policy Monte Carlo;\n";
			cout << "Enter 8 for Softmax off policy Monte Carlo;\n\n";
			cin >> selection;

			if ( selection < 0 || selection > 8 )
				cout << "Invalid selection, please enter one of the following:\n\n";

			} while ( selection < 0 || selection > 8 );

			pred->setAlgorithm(selection);
			pred->resetQ(15);
		}
		break;

		// EXIT PROGRAM
		case 0:
			cout << "Goodbye!\n\n\n";
			continue;

		default:
			cout << "Invalid selection, please enter one of the following:\n\n";
			continue;

        }	// Switch menuSelect

	timer = clock() - timer;
	cout << "\nThis operation took " << ((float)timer)/CLOCKS_PER_SEC << " seconds.\n\n\n";
    } while (menuSelect != 0);

	return 0;
}

